home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 12 - 1996 / 12.06 Jun 96 / MutantLife.c < prev   
Encoding:
Text File  |  1996-06-07  |  27.1 KB  |  944 lines  |  [TEXT/R*ch]

  1. /*
  2.   8 April 1996.
  3.   Submission to MacTech Programmer's challenge for April-96.
  4.   Copyright 1996, Ernst Munter, Kanata, ON, Canada.
  5.  
  6.                  "Mutant Life"
  7.  
  8. | Revisions 7 April 1996:
  9. | In "PropagateLife", added check to return correct
  10. | generation count with an empty map, and no spontaneous
  11. | birth.
  12. | Added #define LARGE_BITMAPS to allow trading of 20% space
  13. | for 3% loss in speed with large maps
  14.  
  15. | Revision 8 April 1996:
  16. | In "PropagateLife", reduced number of iterations of main
  17. | loop by one, and added special exit code.
  18. | This solves the problem with the empty map; but it also
  19. | reduces the time for all runs (40% saving on a single
  20. | generation run).
  21.  
  22.   Problem Statement
  23.   -----------------
  24.   The challenge is to write a fast program that computes the
  25.   Life-like world some generations into the future,  Inter-
  26.   mediate generations need not necessarily be computed, but
  27.   to me at least, it seems we must process one generation at
  28.   a time.
  29.  
  30.   The birth and death rules are specified as bit maps which
  31.   determine changes as a function of any combination of the
  32.   number of cell neighbors (0 to 8), giving rise to 2**18
  33.   possible rule sets.
  34.  
  35.   Another requirement is that the propagation function stop
  36.   as soon as two consecutive worlds are identical.
  37.  
  38.   Additional memory is limited to 1MB plus up to 10 times
  39.   the size of the original bitmap.
  40.  
  41.   Solution Strategy
  42.   -----------------
  43.   We copy the starting bitmap to an internal representation;
  44.   process this for the required number of generations, or
  45.   until we see no change; and then copy the final state back
  46.   to the original bitmap location.
  47.  
  48.   The internal cell format includes the state as well as the
  49.   neighbor count of each cell.
  50.  
  51.   The propagation process consists of two phases for each
  52.   generation: phase 1 in which all changes are used to
  53.   update the neighbor counts, and phase 2 in which the
  54.   neighbor counts are re-evaluated, together with the
  55.   current state, to determine the change to the next state.
  56.  
  57.   Since usually, not all of the cell map changes, it is
  58.   only necessary to process those cells, and their immediate
  59.   neighbors, that do change.
  60.  
  61.   Data Structure
  62.   --------------
  63.   Because of memory limitation, and in the interest of speed
  64.   blocks of 32 cells are stored and processed together.
  65.  
  66.   A "CellBlock" of 32 cells is a 32-byte structure which
  67.   contains cell states, cell changes, counters, and pointers
  68.   to allow cell blocks to be chained into linked lists.
  69.  
  70.   A number of flag bits are stored with each block to
  71.   allow marking of border blocks which require special
  72.   computation to determine the neighbor cells (wrapping).
  73.  
  74.   The counts are stored modulo-9 arithmetic, A 13 bit
  75.   counter holds the neighbor counts for 4 cells, and there
  76.   are 8 such counters located in each cell block.
  77.  
  78.   CellBlocks are allocated dynamically.
  79.  
  80.   Computation and Tables
  81.   ----------------------
  82.   We must perform 2 kinds of computation:
  83.  
  84.   Count Updates
  85.   -------------
  86.   To update the neighbor counts we determine the addresses
  87.   of the neighbors and increment or decrement each modulo-9
  88.   counter depending on the change of state to 0 or 1,
  89.  
  90.   The counter update function is fixed (not dependent on
  91.   birth or death rules).  The changes in a row of 10 cells
  92.   affect exactly 8 counts in the same row and the blocks
  93.   above and below.  Hence a lookup table with 1024 entries
  94.   can be used to provide the pre-computed sums of power-9
  95.   products with 1 or 0, for two of the 13-bit counters
  96.   which are conveniently stored as a pair in a single word.
  97.  
  98.   State update and its rules
  99.   --------------------------
  100.   To determine the state change of a cell we need consider
  101.   only the state of the cell, the neighbor count, and the
  102.   current set of birth/death rules.
  103.  
  104.   Given that 4 counts are stored, munged together in a
  105.   single 13-bit modulo-9 counter, we can also use a look-up
  106.   table for this function.  The rules table contains 9*9*9*9
  107.   entries of 1 byte each, where each byte contains a 4-bit
  108.   birth field, and a 4-bit death field, simply derived from
  109.   the bits in the given birth/deathRules selected according
  110.   to the four neighbor counts implied by the table address.
  111.  
  112.   This rules table must be computed when PropagateLife is
  113.   called, to reflect the current rules.
  114.  
  115.   Assuming that PropagateLife might be called frequently
  116.   in succession, often with the same rules, we can avoid
  117.   re-computing this table unnecessarily.
  118.  
  119.   And since we can use a "reasonable" amount of static
  120.   memory (up to 1MB, say), we can store a fairly big
  121.   rule book of many different rules.  This would allow
  122.   alternating rules to be handled efficiently as well.
  123.  
  124.   Hence, all left over available (permitted) memory is used
  125.   for the rule book.  The 18-bits of concatenated birth and
  126.   death rules are hashed into a page index to quickly locate
  127.   a previously computed rules page.
  128.  
  129.   Other Assumptions
  130.   -----------------
  131.   cells is a bitmap where
  132.     cells.bounds.top=cells.bounds.left==0
  133.     cells.bounds.bottom - cells.bounds.top >= 3
  134.     cells.bounds.right - cells.bounds.left >= 3
  135.  
  136.   The maximum static memory limit can be #defined,
  137.     minimum 15K.
  138.  
  139.   The function allocates dynamic memory equivalent to
  140.   8 more bitmaps + 32 bytes. It returns 0 if malloc fails.
  141.  
  142.   "Spontaneous birth" is allowed, (birthRules LSB set).
  143. */
  144.  
  145. /***** My header file, please adapt as needed **********/
  146.  
  147. #include <stdlib.h>
  148. #include <stdio.h>
  149. #include <memory.h>
  150.  
  151. struct Rect {
  152.         short           top;
  153.         short           left;
  154.         short           bottom;
  155.         short           right;
  156. };
  157.  
  158. struct BitMap {
  159.         void*           baseAddr;
  160.         short           rowBytes;
  161.         Rect            bounds;
  162. };
  163.  
  164. #ifdef __BORLANDC__
  165. long pascal PropagateLife(
  166. #else
  167. pascal long PropagateLife(
  168. #endif
  169.      BitMap cells,
  170.      long numGenerations,
  171.      short birthRules,
  172.      short deathRules);
  173.  
  174. /******************** End of header *******************/
  175.  
  176. // Define amount of static memory to be available,
  177. // minimum 15K:
  178. // the value of 1MB permits 158 rule pages to be stored
  179.  
  180. #define availableStatic 0x100000L
  181.  
  182. // You can reduce the size of the program by about 20% by
  183. // setting LARGE_BITMAPS to 0.
  184. // But runtime for large worlds (1000x1000) goes up 3-4%.
  185. // Normally, we would go with the shorter program, but in
  186. // this challenge, 3% might make a lot of difference:
  187.  
  188. #define LARGE_BITMAPS 1
  189.  
  190. /************ Type Definitions *************************/
  191.  
  192. #define ulong  unsigned long
  193. #define ushort unsigned short
  194. #define uchar  unsigned char
  195.  
  196. struct       CellBlock {
  197.   ulong      state;
  198.   ulong      change;
  199.   CellBlock* link1;
  200.   CellBlock* link2;
  201.   long       count[4];
  202. };
  203. typedef struct CellBlock CellBlock;
  204.  
  205. struct       RulesPage {
  206.   int        birthRule;
  207.   int        deathRule;
  208.   uchar      rules[81*81];
  209.   char       pad[3];
  210. };
  211. typedef struct RulesPage RulesPage;
  212.  
  213. struct       Bits2Counts {
  214.   long       UD;
  215.   long       LR;
  216. };
  217. typedef struct Bits2Counts Bits2Counts;
  218.  
  219. /*************** Function Prototypes *******************/
  220.  
  221. uchar*     MakeRuleTable(
  222.            int        b,
  223.            int        d);
  224.  
  225. CellBlock* LoadCells(
  226.            BitMap     cells,
  227.            int        width,
  228.            int        padWords,
  229.            CellBlock* cb,
  230.            CellBlock* L1);
  231.  
  232. CellBlock* LoadCellsSpontaneous(
  233.            BitMap     cells,
  234.            int        width,
  235.            int        padWords,
  236.            CellBlock* cb,
  237.            CellBlock* L1);
  238.  
  239. CellBlock* UpdateCounts(
  240.            CellBlock* cb,
  241.            CellBlock* L2,
  242.            int        width,
  243.            int        size,
  244.            int        lastColumn,
  245.            long       rightMask);
  246.  
  247. #if LARGE_BITMAPS
  248. CellBlock* UpdateCountsNoWrap(
  249.            CellBlock* cb,
  250.            CellBlock* L2,
  251.            int        width);
  252. #endif
  253.  
  254. ulong      ComputeStateChange(
  255.            CellBlock* cb,
  256.            uchar*     rule);
  257.  
  258. void       UnloadCells(
  259.            CellBlock* cb,
  260.            int        size,
  261.            void*      baseAddr);
  262.  
  263. void       UnloadPaddedCells(
  264.            BitMap     cells,
  265.            int        width,
  266.            int        padWords,
  267.            CellBlock* cb);
  268.  
  269. /******************** Static Data **********************/
  270.  
  271. #define bcUD(i) (                                       \
  272.  ((((i)>>5)&1)*729L)+                                   \
  273.  ((((i)>>4)&1)*810L)+                                   \
  274.  ((((i)>>3)&1)*819L)+                                   \
  275.  ((((i)>>2)&1)*91L)+                                    \
  276.  ((((i)>>1)&1)*10L)+                                    \
  277.  ((i)&1)                                                \
  278. )
  279.  
  280. #define bcLR(i) (                                       \
  281.  ((((i)>>5)&1)*729L)+                                   \
  282.  ((((i)>>4)&1)*81L)+                                    \
  283.  ((((i)>>3)&1)*738L)+                                   \
  284.  ((((i)>>2)&1)*82L)+                                    \
  285.  ((((i)>>1)&1)*9L)+                                     \
  286.  ((i)&1)                                                \
  287. )
  288.  
  289. #define bc(i) {                                         \
  290.    (bcUD((i)>>4)<<13)+bcUD(i),(bcLR((i)>>4)<<13)+bcLR(i)}
  291.  
  292. #define bc4(i)                                          \
  293.         bc(i),bc(i+1),bc(i+2),bc(i+3)
  294. #define bc16(i)                                         \
  295.         bc4(i),bc4(i+0x4),bc4(i+0x8),bc4(i+0xC)
  296. #define bc64(i)                                         \
  297.         bc16(i),bc16(i+0x10),bc16(i+0x20),bc16(i+0x30)
  298. #define bc256(i)                                        \
  299.         bc64(i),bc64(i+0x40),bc64(i+0x80),bc64(i+0xC0)
  300.  
  301. static Bits2Counts BC[0x400] = {
  302.   bc256(0),bc256(0x100),bc256(0x200),bc256(0x300)
  303. };
  304.  
  305. #define numRulesPages                                   \
  306.       ((availableStatic-sizeof(BC)-16)/sizeof(RulesPage))
  307.  
  308. static RulesPage rulesCache[numRulesPages];
  309.  
  310. /********************** Constants **********************/
  311.  
  312. #define MSB         0x80000000L
  313. #define LSB         0x00000001L
  314.  
  315. #define UP          0x40000000L
  316. #define DOWN        0x20000000L
  317. #define LEFT        0x10000000L
  318. #define RIGHT       0x08000000L
  319.  
  320. #define IS_U_BORDER(cb) (cb->count[0] & UP)
  321. #define IS_D_BORDER(cb) (cb->count[0] & DOWN)
  322. #define IS_L_BORDER(cb) (cb->count[0] & LEFT)
  323. #define IS_R_BORDER(cb) (cb->count[0] & RIGHT)
  324.  
  325. /******************* Top level function ****************/
  326.  
  327. #ifdef __BORLANDC__
  328. long pascal PropagateLife(
  329. #else
  330. pascal long PropagateLife(
  331. #endif
  332.   BitMap cells,
  333.   long   numGenerations,
  334.   short  birthRules,
  335.   short  deathRules) {
  336.  
  337.   int        width=(cells.bounds.right+31)>>5;
  338.   int        lastColumn=(cells.bounds.right-1) & 31;
  339.   long       rightMask=0xFFFFFFFF << (31-lastColumn);
  340.   int        size=width*cells.bounds.bottom;
  341.   int        padWords=(cells.rowBytes>>2)-width;
  342.   long       gen;
  343.   long*      allocMem;
  344.   CellBlock* cb;
  345.   CellBlock* L1;
  346.   CellBlock* L2;
  347.   uchar*     rule;
  348.  
  349. // Get memory for cell blocks, 1 block per 32 cells:
  350.  
  351.  if (0==(allocMem=(long*)malloc(32+size*sizeof(CellBlock))))
  352.         return 0;
  353.  
  354. // Align cell blocks with cache-line boundary (32-byte):
  355.  
  356.   { char* temp=(char*)allocMem;
  357.     temp+=(32-(ulong)temp) & 31;
  358.     cb=(CellBlock*)temp;
  359.   }
  360.  
  361. // Clear all cell blocks:
  362.  
  363.   memset(cb,0,size*sizeof(CellBlock));
  364.  
  365. // Establish the rules look-up table in static memory:
  366.  
  367.   rule=MakeRuleTable(birthRules,deathRules);
  368.  
  369. // Copy BitMap cells into CellBlock structures and link:
  370. // Usually, only non-empty cells are linked, but
  371. // if birthRules include a "spontaneous birth" bit,
  372. // all cells must be linked.
  373.  
  374.   if (birthRules & 1)
  375.     L1=LoadCellsSpontaneous(cells,width,padWords,cb,cb-1);
  376.   else L1=LoadCells(cells,width,padWords,cb,cb-1);
  377.   L2=L1;
  378.  
  379.   for (gen=1;;gen++) {
  380.  
  381. // Linked list 1 contains cell blocks with a state change.
  382. // The state changes are applied to the cell states.
  383. // Loop 1 traverses list 1 and updates the counts of all
  384. // affected cells in neighboring blocks and itself.
  385. // If any counts change, the block is linked into list 2,
  386. // unless it is already there.
  387.  
  388.     while (L1>=cb) {
  389. #if LARGE_BITMAPS
  390.       if ((L1->count[0] & (UP | DOWN | LEFT | RIGHT)) == 0)
  391.         L2=UpdateCountsNoWrap(L1,L2,width);
  392.       else
  393. #endif
  394.       L2=UpdateCounts(L1,L2,width,size,lastColumn,rightMask);
  395.       L1=L1->link1;
  396.     }
  397.  
  398. // List 1 is now empty.
  399. // Loop 2 finds the cell changes in each block of list 2,
  400. // using the current states and the neighbor counts.
  401. // If any state changes, the block is put back into list 1.
  402.  
  403.     while (L2>=cb) {
  404.       CellBlock* next=L2->link2;
  405.       if (ComputeStateChange(L2,rule)) {
  406.         L2->link1=L1;
  407.         L1=L2;
  408.       }
  409.       L2->link2=0;
  410.       L2=next;
  411.     }
  412.  
  413. // If list 1 is empty (no change) we can make a fast exit:
  414.  
  415.     if (L1<cb) {
  416.       if (gen==1) goto quick_exit; // nothing changed!
  417.       break;
  418.     }
  419.     if (gen>=numGenerations) break;
  420.   }
  421.  
  422. // Apply last changes to cells in list 1:
  423.  
  424.   while (L1>=cb) {
  425.     L1->state ^= L1->change;
  426.     L1=L1->link1;
  427.   }
  428.  
  429. // The final states of all cells in the private cell blocks
  430. // are copied back into the external BitMap storage.
  431. // A slightly slower function provides for the uncommon case
  432. // when there are extra unused words beyond the right bound.
  433.  
  434.   if (padWords==0) UnloadCells(cb,size,cells.baseAddr);
  435.   else UnloadPaddedCells(cells,width,padWords,cb);
  436.  
  437. // Return all allocated dynamic memory to the system:
  438. quick_exit:
  439.   free(allocMem);
  440.  
  441.   return gen;
  442. }
  443.  
  444. /***************** Macros used in local functions ******/
  445.  
  446. // SETBLOCK is used in LoadCells(..)
  447. #define SETBLOCK(flag)                                  \
  448. { ulong c32=*bm++;                                      \
  449.   cb->count[0]=flag;                                    \
  450.   if (c32) {                                            \
  451.     cb->change=c32;                                     \
  452.     cb->link1=L1;                                       \
  453.     cb->link2=L1;                                       \
  454.     L1=cb;                                              \
  455.   }                                                     \
  456.   cb++;                                                 \
  457. }
  458.  
  459. // SETBLOCKs is used in LoadCellsSpontaneous(..)
  460. #define SETBLOCKs(flag)                                 \
  461. { ulong c32=*bm++;                                      \
  462.   cb->count[0]=flag;                                    \
  463.   cb->change=c32;                                       \
  464.   cb->link1=L1;                                         \
  465.   cb->link2=L1;                                         \
  466.   L1=cb;                                                \
  467.   cb++;                                                 \
  468. }
  469.  
  470. // LINK is used in UpdateCounts(..)
  471. #define LINK(cell)                                      \
  472. { if (((cell)->link2)==0) {                             \
  473.     (cell)->link2=L2;                                   \
  474.     L2=cell;                                            \
  475.   }                                                     \
  476. }
  477.  
  478. // CHANGE_COUNT is used in UpdateCounts(..)
  479. #define CHANGE_COUNT(cell,ctr,delta);                   \
  480. { long cnt=(cell)->count[ctr] | MSB;                    \
  481.   (cell)->count[ctr]=cnt+(delta);                       \
  482. }
  483.  
  484. // The following three macros are used in UpdateCounts(..)
  485. #define UPDATE_COMMON(ctr)                              \
  486. { delta=BC[newIndex].UD-BC[oldIndex].UD;                \
  487.   CHANGE_COUNT(cUP,ctr,delta);                          \
  488.   CHANGE_COUNT(cDN,ctr,delta);                          \
  489.   delta=BC[newIndex].LR-BC[oldIndex].LR;                \
  490.   CHANGE_COUNT(cb,ctr,delta);                           \
  491. }
  492.  
  493. // C/C++ does not understand negative shifts, so
  494. // we make separate macros for left and right shifts;
  495. #define UPDATE_UD(shft,ctr)                             \
  496. { int oldIndex=(oldState >> shft) & 0x3FF;              \
  497.   int newIndex=(newState >> shft) & 0x3FF;              \
  498.   UPDATE_COMMON(ctr)                                    \
  499. }
  500.  
  501. #define UPDATE_UD_(shft,ctr)                            \
  502. { int oldIndex=(oldState << shft) & 0x3FF;              \
  503.   int newIndex=(newState << shft) & 0x3FF;              \
  504.   UPDATE_COMMON(ctr)                                    \
  505. }
  506.  
  507. /***************** Local Functions *********************/
  508.  
  509. uchar* MakeRuleTable(int b,int d) {
  510.  
  511. // Checks if a valid rules table exists for the current
  512. // rules, and computes a new table if necessary.
  513.  
  514. int pageNumber=((b << 9) + d) % numRulesPages;
  515. RulesPage* rp=rulesCache+pageNumber;
  516.   if ((rp->birthRule != b)
  517.   ||  (rp->deathRule != d)) {
  518.  
  519.     int q,r,s,Q,R,S;
  520.     int t0,t1,t2,t3,t4,t5,t6,t7,t8;
  521.     unsigned char* t=rp->rules;
  522.     rp->birthRule = b;
  523.     rp->deathRule = d;
  524.     b=b<<4;;
  525.     t0=((d)&1)    | ((b)&0x10);
  526.     t1=((d>>1)&1) | ((b>>1)&0x10);
  527.     t2=((d>>2)&1) | ((b>>2)&0x10);
  528.     t3=((d>>3)&1) | ((b>>3)&0x10);
  529.     t4=((d>>4)&1) | ((b>>4)&0x10);
  530.     t5=((d>>5)&1) | ((b>>5)&0x10);
  531.     t6=((d>>6)&1) | ((b>>6)&0x10);
  532.     t7=((d>>7)&1) | ((b>>7)&0x10);
  533.     t8=((d>>8)&1) | ((b>>8)&0x10);
  534.     t[0]=(uchar)t0;
  535.     t[1]=(uchar)t1;
  536.     t[2]=(uchar)t2;
  537.     t[3]=(uchar)t3;
  538.     t[4]=(uchar)t4;
  539.     t[5]=(uchar)t5;
  540.     t[6]=(uchar)t6;
  541.     t[7]=(uchar)t7;
  542.     t[8]=(uchar)t8;
  543.     t+=6561-9;
  544.     for (s=8;s>=0;s--) {
  545.       S=rp->rules[s]<<3;
  546.       for (r=8;r>=0;r--) {
  547.         R=S | (rp->rules[r]<<2);
  548.         for (q=8;q>=0;q--) {
  549.           Q=R | (rp->rules[q]<<1);
  550.           t[0]=(uchar)(Q | t0);
  551.           t[1]=(uchar)(Q | t1);
  552.           t[2]=(uchar)(Q | t2);
  553.           t[3]=(uchar)(Q | t3);
  554.           t[4]=(uchar)(Q | t4);
  555.           t[5]=(uchar)(Q | t5);
  556.           t[6]=(uchar)(Q | t6);
  557.           t[7]=(uchar)(Q | t7);
  558.           t[8]=(uchar)(Q | t8);
  559.           t-=9;
  560.         }
  561.       }
  562.     }
  563.   }
  564.   return rp->rules;
  565. }
  566.  
  567. CellBlock* LoadCells(
  568.            BitMap     cells,
  569.            int        width,
  570.            int        padWords,
  571.            CellBlock* cb,
  572.            CellBlock* L1) {
  573.  
  574. // Copies the states of all cells in the bitmap into
  575. // the cell blocks, as state changes to trigger evaluation.
  576. // Sets border flags as needed.
  577. // Links all non-empty cell blocks in both lists.
  578. // The special case of "spontaneous birth" is handled by
  579. //   a separate function LoadCellsSpontaneous(..)
  580.  
  581. ulong* bm=(ulong*)cells.baseAddr;
  582. int    x,y;
  583.  
  584.   if (width>1) {
  585.  
  586. //top edge:
  587.     SETBLOCK(UP+LEFT);
  588.     for (x=1;x<width-1;x++) SETBLOCK(UP);
  589.     SETBLOCK(UP+RIGHT);
  590.     bm+=padWords;
  591.  
  592. //middle rows:
  593.     for (y=1;y<cells.bounds.bottom-1;y++) {
  594.       SETBLOCK(LEFT);
  595.       for (x=1;x<width-1;x++) SETBLOCK(0);
  596.       SETBLOCK(RIGHT);
  597.       bm+=padWords;
  598.     }
  599.  
  600. //bottom edge:
  601.     SETBLOCK(DOWN+LEFT);
  602.     for (x=1;x<width-1;x++) SETBLOCK(DOWN);
  603.     SETBLOCK(DOWN+RIGHT);
  604.   } else {
  605.  
  606. //case of bit map <= 32 cells wide
  607. //top edge:
  608.     SETBLOCK(UP+LEFT+RIGHT);
  609.     bm+=padWords;
  610. //middle rows:
  611.     for (y=1;y<cells.bounds.bottom-1;y++) {
  612.       SETBLOCK(LEFT+RIGHT);
  613.       bm+=padWords;
  614.     }
  615. //bottom edge:
  616.     SETBLOCK(DOWN+LEFT+RIGHT);
  617.   }
  618.   return L1;
  619. }
  620.  
  621. CellBlock* UpdateCounts(
  622.            CellBlock* cb,
  623.            CellBlock* L2,
  624.            int        width,
  625.            int        size,
  626.            int        lastColumn,
  627.            long       rightMask) {
  628.  
  629. // Processes one cell block: locates its neighbor blocks,
  630. // and updates their counters according to the state changes
  631. // of the cells in the center block.
  632.  
  633. // The 32 cells of a block are divided into 4 overlapping
  634. // groups, corresponding to the 4 counter words affected.
  635. // Only counters whose count changes are accessed, and so
  636. // flagged (by setting MSB).
  637.  
  638. // Notably, right and left neighboring cell blocks are only
  639. // affected if the first or last bits of the center block
  640. // change.
  641.  
  642. // The function deals with a number of special cases such
  643. // as wrapping, and the possibly partially filled block at
  644. // the right margin of the bitmap.
  645.  
  646. ulong      oldState=cb->state;
  647. ulong      theChange=cb->change;
  648. ulong      newState;
  649. ulong      lastBit;
  650. CellBlock* cUP=cb-width;
  651. CellBlock* cDN=cb+width;
  652. long       delta;
  653.  
  654.   if (IS_U_BORDER(cb)) cUP+=size;
  655.   if (IS_D_BORDER(cb)) cDN-=size;
  656.   if (IS_R_BORDER(cb)) {
  657.     theChange &= rightMask;
  658.     lastBit=0x80000000>>lastColumn;
  659.   } else lastBit=LSB;
  660.  
  661.   newState=oldState ^ theChange;
  662.   cb->state=newState;
  663.   if (theChange & 0xFF800000) {
  664.     UPDATE_UD(23,0);
  665.     if (theChange & MSB) {                      //carry left
  666.       int ctr=3;
  667.       int offset=-1;
  668.       delta=((newState >>30) & 2) - 1;
  669.       if (IS_L_BORDER(cb)) {                    //wrap
  670.         ctr = lastColumn >> 3;
  671.         offset+=width;
  672.         switch (lastColumn & 7) {
  673.         case 0:delta = (delta<<13)*729; break;
  674.         case 1:delta = (delta<<13)*81; break;
  675.         case 2:delta = (delta<<13)*9; break;
  676.         case 3:delta = (delta<<13); break;
  677.         case 4:delta *= 729; break;
  678.         case 5:delta *= 81; break;
  679.         case 6:delta *= 9; break;
  680.         }
  681.       }
  682.       CHANGE_COUNT(cUP+offset,ctr,delta);
  683.       LINK(cUP+offset);
  684.       CHANGE_COUNT(cb+offset,ctr,delta);
  685.       LINK(cb+offset);
  686.       CHANGE_COUNT(cDN+offset,ctr,delta);
  687.       LINK(cDN+offset);
  688.     }
  689.   }
  690.   if (theChange & 0x01FF8000) UPDATE_UD(15,1);
  691.   if (theChange & 0x0001FF80) UPDATE_UD( 7,2);
  692.   if (theChange & 0x000001FF) UPDATE_UD_(1,3);
  693.   if (theChange & lastBit) {                   //carry right
  694.     int offset=+1;
  695.     if (IS_R_BORDER(cb)) {                      //wrap
  696.       delta = (((newState >> (31-lastColumn)) << 1) & 2) -1;
  697.       offset -= width;
  698.     } else delta = (((newState << 1) & 2) - 1);
  699.     delta *= (729L<<13);
  700.     CHANGE_COUNT(cUP+offset,0,delta);
  701.     LINK(cUP+offset);
  702.     CHANGE_COUNT(cb+offset,0,delta);
  703.     LINK(cb+offset);
  704.     CHANGE_COUNT(cDN+offset,0,delta);
  705.     LINK(cDN+offset);
  706.   }
  707.  
  708.   LINK(cUP);
  709.   LINK(cDN);
  710.   LINK(cb);
  711.   return L2;
  712. }
  713.  
  714. #if LARGE_BITMAPS
  715. CellBlock* UpdateCountsNoWrap(
  716.            CellBlock* cb,
  717.            CellBlock* L2,
  718.            int        width) {
  719.  
  720. // A stream-lined version of UpdateCounts(..)
  721. // for interior (non-border) cell blocks which cannot wrap.
  722.  
  723. ulong      oldState=cb->state;
  724. ulong      theChange=cb->change;
  725. ulong      newState;
  726. CellBlock* cUP=cb-width;
  727. CellBlock* cDN=cb+width;
  728. long       delta;
  729.  
  730.   newState=oldState ^ theChange;
  731.   cb->state=newState;
  732.   if (theChange & 0xFF800000) {
  733.     UPDATE_UD(23,0);
  734.     if (theChange & MSB) {                      //carry left
  735.       int ctr=3;
  736.       int offset=-1;
  737.       delta=((newState >>30) & 2) - 1;
  738.       CHANGE_COUNT(cUP+offset,ctr,delta);
  739.       LINK(cUP+offset);
  740.       CHANGE_COUNT(cb+offset,ctr,delta);
  741.       LINK(cb+offset);
  742.       CHANGE_COUNT(cDN+offset,ctr,delta);
  743.       LINK(cDN+offset);
  744.     }
  745.   }
  746.   if (theChange & 0x01FF8000) UPDATE_UD(15,1);
  747.   if (theChange & 0x0001FF80) UPDATE_UD( 7,2);
  748.   if (theChange & 0x000001FF) UPDATE_UD_(1,3);
  749.   if (theChange & LSB) {                       //carry right
  750.     int offset=+1;
  751.     delta = (((newState << 1) & 2) - 1) * (729L<<13);
  752.     CHANGE_COUNT(cUP+offset,0,delta);
  753.     LINK(cUP+offset);
  754.     CHANGE_COUNT(cb+offset,0,delta);
  755.     LINK(cb+offset);
  756.     CHANGE_COUNT(cDN+offset,0,delta);
  757.     LINK(cDN+offset);
  758.   }
  759.  
  760.   LINK(cUP);
  761.   LINK(cDN);
  762.   LINK(cb);
  763.   return L2;
  764. }
  765. #endif
  766.  
  767. ulong ComputeStateChange(CellBlock* cb,uchar* rule) {
  768.  
  769. // Computes the state change for 32 cells in a cell block.
  770.  
  771. // The 4 counters are flagged, and only those counters
  772. // that actually changed need to be considered.
  773.  
  774. // The algorithm computes 32-bit birth and death masks
  775. // from the counts: Each counter word cb->count[i]
  776. // contains two 13-bit counter values.  These are
  777. // used successively to index into the rules table
  778. // each time extracting two 4-bit fields, for births
  779. // and deaths according to the 4 modulo-9 counts
  780. // inherent in the counters.  The 4-bit fields from
  781. // all lookups (or 0) are separately stacked into 32-bit
  782. // birth and death masks.
  783.  
  784. // Note: counters that are known not to have changed
  785. //       (MSB clear) cannot effect a state change and are
  786. //       skipped in the evaluation of counts.
  787.  
  788. // In each bit position then, each state bit selects the
  789. // corresponding birth or death mask as follows:
  790.  
  791. // A 0-state selects the birth bit, and a 1-state
  792. // selects the death bit.
  793.  
  794. // oldState  birth  death  change
  795. //    0        0      x      0
  796. //    0        1      x      1
  797. //    1        x      0      0
  798. //    1        x      1      1
  799.  
  800. // This is conveniently expressed as (in Pascal):
  801. //   change := (old AND death) OR (NOT old AND birth)
  802.  
  803. // And we can perform this function on all 32 bits at once.
  804.  
  805. // PowerPC has an instruction (rlwinm) that can & and >>
  806. // immediate, all in one clock cycle.
  807. // Let's hope the compiler knows how to use it here.
  808.  
  809. ulong stateChange;
  810. ulong db4_hi,db4_lo,d32=0,b32=0;
  811. long  cnt;
  812.  
  813.   if ((cnt=cb->count[0])<0) {
  814.     cb->count[0] = cnt & (~MSB);
  815.     db4_hi = rule[(cnt>>13) & 0x1FFF];//mask off flag bits
  816.     db4_lo = rule[ cnt      & 0x1FFF];
  817.     d32 |= ((db4_hi & 0x0F) << 28)|((db4_lo & 0x0F) << 24);
  818.     b32 |= ((db4_hi & 0xF0) << 24)|((db4_lo & 0xF0) << 20);
  819.   }
  820.   if ((cnt=cb->count[1])<0) {
  821.     cnt &= (~MSB);
  822.     cb->count[1] = cnt;
  823.     db4_hi = rule[cnt >> 13];
  824.     db4_lo = rule[cnt &  0x1FFF];
  825.     d32 |= ((db4_hi & 0x0F) << 20)|((db4_lo & 0x0F) << 16);
  826.     b32 |= ((db4_hi & 0xF0) << 16)|((db4_lo & 0xF0) << 12);
  827.   }
  828.   if ((cnt=cb->count[2])<0) {
  829.     cnt &= (~MSB);
  830.     cb->count[2] = cnt;
  831.     db4_hi = rule[cnt >> 13];
  832.     db4_lo = rule[cnt &  0x1FFF];
  833.     d32 |= ((db4_hi & 0x0F) << 12)|((db4_lo & 0x0F) <<  8);
  834.     b32 |= ((db4_hi & 0xF0) <<  8)|((db4_lo & 0xF0) <<  4);
  835.   }
  836.   if ((cnt=cb->count[3])<0) {
  837.     cnt &= (~MSB);
  838.     cb->count[3] = cnt;
  839.     db4_hi = rule[cnt >> 13];
  840.     db4_lo = rule[cnt &  0x1FFF];
  841.     d32 |= ((db4_hi & 0x0F) <<  4)| (db4_lo & 0x0F);
  842.     b32 |=  (db4_hi & 0xF0)       |((db4_lo & 0xF0) >> 4);
  843.   }
  844.  
  845.   stateChange = (cb->state & d32)
  846.               | (~(cb->state) & b32);
  847.   cb->change=stateChange;
  848.   return stateChange;
  849. }
  850.  
  851. void UnloadCells(CellBlock* cb,int size,void* baseAddr) {
  852.  
  853. // Simple sequential copy of all cell states from
  854. // cell blocks to bit map, loop unrolled once.
  855.  
  856.   ulong* bm=(ulong*)baseAddr;
  857.   while (size>1) {
  858.     size-=2;
  859.     bm[0]=cb[0].state;
  860.     bm[1]=cb[1].state;
  861.     bm+=2;
  862.     cb+=2;
  863.   }
  864.   if (size) *bm=cb->state;
  865. }
  866.  
  867. //
  868. // The following 2 functions will handle the loading and
  869. // unloading of cell blocks for the less likely scenarioes.
  870. // Keeping these complications out of the mainstream functions
  871. // above is really only a tweak to not waste time on frequent
  872. // checks, noticeable only with very short runs.
  873.  
  874. CellBlock* LoadCellsSpontaneous(
  875.            BitMap     cells,
  876.            int        width,
  877.            int        padWords,
  878.            CellBlock* cb,
  879.            CellBlock* L1) {
  880.  
  881. // Same as LoadCells(..) above, but handles the special case
  882. // of "spontaneous birth" by linking all cells.
  883.  
  884. ulong* bm=(ulong*)cells.baseAddr;
  885. int    x,y;
  886.  
  887.   if (width>1) {
  888.  
  889. //top edge:
  890.     SETBLOCKs(UP+LEFT);
  891.     for (x=1;x<width-1;x++) SETBLOCKs(UP);
  892.     SETBLOCKs(UP+RIGHT);
  893.     bm+=padWords;
  894.  
  895. //middle rows:
  896.     for (y=1;y<cells.bounds.bottom-1;y++) {
  897.       SETBLOCKs(LEFT);
  898.       for (x=1;x<width-1;x++) SETBLOCKs(0);
  899.       SETBLOCKs(RIGHT);
  900.       bm+=padWords;
  901.     }
  902.  
  903. //bottom edge:
  904.     SETBLOCKs(DOWN+LEFT);
  905.     for (x=1;x<width-1;x++) SETBLOCKs(DOWN);
  906.     SETBLOCKs(DOWN+RIGHT);
  907.   } else {
  908.  
  909. //case of bit map <= 32 cells wide
  910. //top edge:
  911.     SETBLOCKs(UP+LEFT+RIGHT);
  912.     bm+=padWords;
  913. //middle rows:
  914.     for (y=1;y<cells.bounds.bottom-1;y++) {
  915.       SETBLOCKs(LEFT+RIGHT);
  916.       bm+=padWords;
  917.     }
  918. //bottom edge:
  919.     SETBLOCKs(DOWN+LEFT+RIGHT);
  920.   }
  921.   return L1;
  922. }
  923.  
  924. void UnloadPaddedCells(
  925.      BitMap     cells,
  926.      int        width,
  927.      int        padWords,
  928.      CellBlock* cb){
  929.  
  930. // Copy all cell states from cell blocks to bit map,
  931. // row by row, skipping unused pad words at the end of
  932. // each row in the bit map.
  933.  
  934. int x,y;
  935. ulong* bm=(ulong*)(cells.baseAddr);
  936.   for (y=0;y<cells.bounds.bottom;y++) {
  937.     for (x=0;x<width;x++) {
  938.       *bm++=cb->state;
  939.       cb++;
  940.     }
  941.     bm+=padWords;
  942.   }
  943. }
  944.